package com.vcs.web;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import jxl.*;
import jxl.write.*;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.ParameterAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
// import org.hibernate.validator.Valid;
import java.util.Iterator;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.vcs.dao.ClientDAO;
import com.vcs.dao.ClientDAOImpl;
import com.vcs.domain.Client;
import com.vcs.domain.Jobseeker;
import com.vcs.domain.Utils;
import com.vcs.util.MailUtil;
import com.vcs.util.VcsConstants;

@SuppressWarnings("serial")
public class ClientAction extends ActionSupport implements ModelDriven<Client>,
		SessionAware, RequestAware, ParameterAware {

	Log log = LogFactory.getLog(ClientAction.class);

	private InputStream inputStream;

	private Client client = new Client();
	private List<Client> clientList = new ArrayList<Client>();
	private ClientDAO clientDAO = new ClientDAOImpl();

	private Map<String, Object> sessionMap;
	private Map<String, Object> requestMap;
	private Map<String, String[]> paramsMap;

	@Override
	public Client getModel() {
		return client;
	}

	@Override
	public void setSession(Map<String, Object> sessionMap) {
		this.sessionMap = sessionMap;
	}

	@Override
	public void setRequest(Map<String, Object> requestMap) {
		this.requestMap = requestMap;
	}

	@Override
	public void setParameters(Map<String, String[]> paramsMap) {
		this.paramsMap = paramsMap;
	}

	public InputStream getInputStream() {
		return inputStream;
	}

	public void setInputStream(InputStream inputStream) {
		this.inputStream = inputStream;
	}

	public String delete() {
		log.info("client being deleted:---> " + client);
		/*
		 * HttpServletRequest request = (HttpServletRequest) ActionContext
		 * .getContext().get(ServletActionContext.HTTP_REQUEST);
		 */
		clientDAO.deleteClient(((Client) (sessionMap
				.get("currentClientProfile"))).getId());
		// remove client from session.
		if (sessionMap.get("currentClientProfile") != null) {
			sessionMap.remove("currentClientProfile");
		}
		return SUCCESS;
	}

	public String edit() {
		log.info("edit()...");
		HttpServletRequest request = (HttpServletRequest) ActionContext
				.getContext().get(ServletActionContext.HTTP_REQUEST);
		client = clientDAO.listClientById(Long.parseLong(request
				.getParameter("id")));
		return SUCCESS;
	}

	/**
	 * Saves a fresh client in database by calling the dao's save() method. Also
	 * sets various fields to their default values
	 * 
	 * @return String
	 */

	public String save() {
		log.info("save()...");

		if (client == null) {
			log.info("CLIENT IS NULL");
			log.info("CLIENT: [" + client + "]");
			return INPUT;
		}
		// prepare and send email for every registration attempt
		String subject = "Alert - New Client is trying to Register";
		String body = "Dear Admin,\n\nA client is trying to register with following details\n"
				+ "\nCompany Name: "
				+ client.getCompanyName()
				+ "\nContact Person: "
				+ client.getContactPerson()
				+ "\nEmail: "
				+ client.getEmail()
				+ "\nContact Number: "
				+ client.getMobile() + "\nOffice phone: " + client.getPhone();

		SendRegistrationAlert regAlert = new SendRegistrationAlert();
		regAlert.setSubject(subject);
		regAlert.setBody(body);

		Thread t = new Thread(regAlert);
		t.start();

		// Check if the username already exists in database. if yes then user
		// should be redirected to the login page with proper validation message

		List<String> allUsernames = clientDAO.getAllUsernames();
		if (allUsernames.contains(client.getUsername())) {
			log.debug("Username is already registerd.");
			addFieldError("username",
					"User Name already registerd, Please choose a different User Name");
		}

		// call validation method.
		validateClientRegForm();
		if (hasFieldErrors()) {
			return INPUT;
		}
		// check if username is admin or not
		if (client.getUsername().equalsIgnoreCase(VcsConstants.ADMIN)) {
			client.setRole(VcsConstants.ADMIN);
		} else {
			client.setRole(VcsConstants.CLIENT);
		}

		// insert profile creation date
		client.setCreatedDate(new java.util.Date());
		client.setUpdateDate(new java.util.Date());
		client.setProfileState(VcsConstants.ACTIVE);
		log.info("CLIENT: " + client);
		clientDAO.save(client);
		return SUCCESS;
	}

	/**
	 * Updates profile once it is saved.
	 * 
	 * @return Status String
	 */

	public String update() {

		// inject client id into client object
		client.setId(((Client) sessionMap.get("client")).getId());

		// inject client's Role in the object
		client.setRole(((Client) sessionMap.get("client")).getRole());

		// inject client's username
		client.setUsername(((Client) sessionMap.get("client")).getUsername());

		// set current date as resume update date.
		client.setUpdateDate(new java.util.Date());

		// Do server side validation
		validateClientRegForm();
		if (hasFieldErrors()) {
			return INPUT;
		}

		log.info("CLIENT: " + client);
		clientDAO.update(client);

		// fetch client information and put in session to refect updated info.
		sessionMap.remove("client");
		sessionMap.put("client", client);
		return SUCCESS;
	}

	// Verify client for registration.
	public String verifyClient() {
		log.info("verifyClient()...");
		String username = client.getUsername();
		String password = client.getPassword();

		if (username == null || username.equals("") || password == null
				|| password.equals("")) {
			addActionError("Invalid User Name or Password");
			return INPUT;
		}

		log.debug("USERNAME:" + username + " PASSWORD: " + password);
		Client clientProfile = clientDAO.getProfileByUsername(username,
				password);
		if (clientProfile != null) {
			logout();
			sessionMap.put("client", clientProfile);
			log.debug("Entered verifyClient() method");
			return SUCCESS;
		} else {
			addActionError("Invalid User Name or Password");
			log.debug("Invalid username or password");
			return INPUT;
		}
	}

	// Destroy client's session, called when client hits the logout link on the
	// header.
	public String logout() {
		Map<String, Object> session = ActionContext.getContext().getSession();
		if (session.get("client") != null) {
			session.remove("client");
		}
		if (session.get("js") != null) {
			session.remove("js");
		}
		log.info("************ USER LOGGED OUT ************");
		// clears everything from the session
		session.clear();
		log.debug(session.isEmpty());
		return SUCCESS;
	}

	/**
	 * This method fetches the list of resumes from the server and allows ADMIN
	 * to view the list
	 * 
	 * @return struts status string
	 */

	public String resumeListOnServer() {
		log.info("resumeListOnServer()...");

		Client c = (Client) sessionMap.get("client");
		if (c != null && c.getRole().equals(VcsConstants.ADMIN)) {
			String opSys = System.getProperty("os.name"); // find OS
			log.info("Operating system is: [" + opSys + "]");

			String dirPath = null;
			String workingDir = "downloads";
			if (opSys.equalsIgnoreCase("Linux")) {

				dirPath = "." + File.separator + workingDir + File.separator;
			} else {
				dirPath = File.separator + workingDir + File.separator;
				log.info("Directory path is : " + dirPath);
			}
			File dir = new File(dirPath);
			String[] names = dir.list();
			log.info("Last modified: " + new Date(dir.lastModified()));

			// sort the resume names based on the nautral order
			// log.info(names.length);
			Map<String, Date> fmap = new HashMap<String, Date>();
			for (String name : names) {
				File f = new File(dirPath + name);
				fmap.put(f.getName(), new Date(f.lastModified()));
				log.info(f.getName() + " -- " + new Date(f.lastModified()));
			}

			// Logic to fetch file name and upload date form database.
			Map<String, String> resMap = clientDAO.getAllResumeNames();

			// TODO sort the map based on values
			List lst = new LinkedList(resMap.entrySet());

			Collections.sort(lst, new Comparator() {
				@SuppressWarnings("rawtypes")
				public int compare(Object first, Object second) {
					return ((Comparable) ((Map.Entry) first).getValue())
							.compareTo(((Map.Entry) second).getValue());
				}
			});

			Map result = new LinkedHashMap();
			for (Iterator it = lst.iterator(); it.hasNext();) {
				Map.Entry entry = (Map.Entry) it.next();
				result.put(entry.getKey(), entry.getValue());
			}

			log.info("result ---> " + result);

			requestMap.put("fmap", result); // contains sorted data based on
											// upload date
			// requestMap.put("resumes", names);
			// requestMap.put("fmap", fmap);
			// requestMap.put("fmap", resMap); this is working.
		} else {
			log.info("A non-Admin user tried to access the resume database");
			return INPUT;
		}
		return SUCCESS;
	}

	/**
	 * Allows ADMIN to download resumes present on server
	 * 
	 * @return struts2 status string
	 */

	public String resumeDownloadAdmin() {

		// fetch resume name from request
		String[] resumeNames = (String[]) paramsMap.get("resumeToDownload");
		String resumeName = null;
		for (String i : resumeNames) {
			log.info("Resume name from request parameters ---> " + i);
			resumeName = i;
		}
		ServletActionContext.getResponse().setHeader("Content-Disposition",
				"attachment; filename=\"" + resumeName + "\"");

		String opSys = System.getProperty("os.name"); // find OS
		log.debug("Operating system is: [" + opSys + "]");

		String fullFileName = null;
		String workingDir = "downloads";

		if (opSys.equalsIgnoreCase("Linux")) {

			fullFileName = "." + File.separator + workingDir + File.separator
					+ resumeName;
		} else {
			fullFileName = File.separator + workingDir + File.separator
					+ resumeName;
		}

		log.debug("Full file path: [" + fullFileName + "]");

		try {
			inputStream = new FileInputStream(new File(fullFileName));
		} catch (FileNotFoundException fnf) {
			log.info("-----------Resume File Not Found ------------");
		}

		return SUCCESS;
	}

	/**
	 * I suppose this is not being used anywhere. Can be removed at a later
	 * point of time
	 * 
	 * @return
	 */

	public String clientRegForm() {
		return "clientRegForm";
	}

	/**
	 * Validates the ClientRegistration and Client profile edit Form
	 */

	public void validateClientRegForm() {
		log.info("validateClientRegForm()...");

		// USERNAME
		if (client.getUsername().contains(" ")) {
			addFieldError("username", "User name should not contain spaces");
		} else if (client.getUsername() == null
				|| client.getUsername().length() < 5
				|| client.getUsername().length() > 15) {
			addFieldError("username",
					"Username should be between 5 to 15 charaters long");
		}/*
		 * else { List<String> allUsernames = clientDAO.getAllUsernames(); if
		 * (allUsernames.contains(client.getUsername())) {
		 * log.info("Username is already registerd."); addFieldError("username",
		 * "User Name already registerd, Please enter a different User Name"); }
		 * }
		 */

		// password validation
		if (client.getPassword().length() < 5
				|| client.getPassword().length() > 15) {
			addFieldError("password",
					"Password should be between 5 to 15 charaters long");
		}
		// Contact Person
		if (client.getContactPerson().length() < 2) {
			addFieldError("contactPerson", "Contact person name is mandatory");
		}
		// Designation
		if (client.getDesignation().length() == 0) {
			addFieldError("designation", "You did not enter designation");
		}

		// Email
		if (client.getEmail().length() == 0 || client.getEmail().equals("")) {
			addFieldError("email", "Please enter your valid email id");
		} else {
			int atIndex = 0;
			int dotIndex = 0;
			if (client.getEmail().contains("@")
					&& client.getEmail().contains(".")) {
				atIndex = client.getEmail().indexOf("@");
				dotIndex = client.getEmail().lastIndexOf(".");

				if (dotIndex < atIndex) {
					addFieldError("email",
							"Invalid email. Please provide your correct email address");
				}
			} else {
				addFieldError("email",
						" Invalid email. Please provide your correct email address");
			}
		}

		if (client.getCompanyProfile().length() < 2) {
			addFieldError("companyProfile", "Company Profile should be entered");
		}
		if (client.getAddress().length() < 10) {
			addFieldError("address",
					"Address is too small, please enter more detiled address");
		}
		if (client.getPincode() < 100000 || client.getPincode() > 999999) {
			addFieldError("pincode", "Invalid pincode");
		}

		// Mobile number
		if (client.getMobile() < 1000000000L
				|| client.getMobile() > 9999999999L) {
			addFieldError("mobile",
					"Invalid Mobile number, should be a 10 digit number only");
		}
		// phone number
		if (client.getPhone() == 0) {
			addFieldError("phone", "You did not enter phone number");
		}

		if (client.getCompanyName().length() == 0
				|| client.getCompanyName() == null) {
			addFieldError("companyName", "You did not enter Company Name");
		}
		// Account Type
		if (client.getAccountType() == null) {
			addFieldError("accountType", "Please select your account type");
		}

	}

}

/**
 * Prepare and send email for successful and unsuccessful client registration
 * attempts. By doing this the client can be contacted if he fails to do a
 * registration.
 * 
 * @author Bharat Sharma
 * 
 */

class SendRegistrationAlert implements Runnable {

	private String subject;
	private String body;

	public void setSubject(String subject) {
		this.subject = subject;
	}

	public void setBody(String body) {
		this.body = body;
	}

	public void run() {
		MailUtil mUtil = new MailUtil();
		mUtil.sendMail("myjob.vcs@gmail.com", "myjob.vcs@gmail.com", subject,
				body);
	}
}
